package gu.simplemq;

import java.util.Collection;
import java.util.Iterator;
import com.google.common.collect.ImmutableMultimap.Builder;

import gu.simplemq.utils.SPIUtils;

import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import static com.google.common.base.Preconditions.checkNotNull;

public class MQContextLoader implements Constant{	
	private final static ImmutableMultimap<MessageQueueType, IMQContext> contexts;
	static final ImmutableMap<MessageQueueType, IMessageQueueFactory> factories;
	private MQContextLoader() {
	}
	
	static {
		Builder<MessageQueueType, IMQContext> builder = ImmutableMultimap.<MessageQueueType, IMQContext>builder();
		ImmutableMap.Builder<MessageQueueType, IMessageQueueFactory> factoryBuilder = ImmutableMap.builder();

		Iterator<IMQContext> itor = SPIUtils.serviceLoaderOf(IMQContext.class).iterator();
		while(itor.hasNext()){
			IMQContext c = itor.next();
			builder.put(c.getMessageQueueType(), c);
			factoryBuilder.put(c.getMessageQueueType(), c.getMessageQueueFactory());
		}
		contexts = builder.build();
		factories = factoryBuilder.build();
	}
	public static IMQContext getMQContext(MessageQueueType implType){
		ImmutableCollection<IMQContext> c = contexts.get(implType);
		switch (c.size()) {
		case 0:
			return null;
		case 1:
			return Lists.newArrayList(c).get(0);
		default:
			logger.warn("Multiple entries with same key: {},first instance returned", implType);
			return Lists.newArrayList(c).get(0); 
		}
	}
	
	public static Collection<IMQContext> getMQContexts(MessageQueueType implType){
		return contexts.get(implType);
	}
	public static IMQContext getMQContextChecked(MessageQueueType implType){
		return checkNotNull(getMQContext(implType),"NOT FOUND Context instance for %s",implType);
	}
	
	public static IMQContext getMQContext(MessageQueueType implType,final String clientImplType){
		ImmutableCollection<IMQContext> c = contexts.get(implType);
		Optional<IMQContext> found = Iterables.tryFind(c, new Predicate<IMQContext>() {
			@Override
			public boolean apply(IMQContext input) {
				return Objects.equal(input.getClientImplType(),clientImplType);
			}
		});
		return found.orNull(); 
	}
	public static IMQContext getMQContextChecked(MessageQueueType implType,final String clientImplType){
		return checkNotNull(getMQContext(implType,clientImplType),"NOT FOUND Context instance for %s:%s",implType,clientImplType);

	}
}
